<template>
    <div>
        <h2>G6 动态数据示例</h2>
        <button @click="addNode">添加节点</button>
        <div ref="container" style="width:100%;height:400px;margin-top:10px;background:#f5f5f5;"></div>
    </div>
</template>

<script setup lang="ts">
// 组件名称定义
defineOptions({ name: 'AntvG6Demo6' });
import { ref, onMounted } from 'vue';
// 引入 G6 图可视化库
import * as G6 from '@antv/g6';

// 获取容器 DOM 的 ref
const container = ref();
// G6 图实例
let graph: any = null;
// 节点计数器，用于生成唯一节点 id
let nodeCount = 2;

// 用 ref 包裹节点和边的数据，确保每次变动都是新对象，便于响应式和 G6 检测数据变化
let nodeMap = ref<Record<string, { id: string, label: string, x: number, y: number }>>({
    node1: { id: 'node1', label: '节点1', x: 100, y: 200 },
    node2: { id: 'node2', label: '节点2', x: 300, y: 200 }
});
let edges = ref([
    { source: 'node1', target: 'node2' }
]);

// 数据安全更新方法：校验边的合法性，生成新数据对象，并用 setData+render 刷新 G6 画布
function safeUpdate() {
    // 1. 校验所有边引用的节点 id 是否存在
    const nodeIds = new Set(Object.keys(nodeMap.value));
    for (const edge of edges.value) {
        if (!nodeIds.has(edge.source) || !nodeIds.has(edge.target)) {
            console.error('边引用了不存在的节点', edge, '当前节点id集合', nodeIds);
            return;
        }
    }
    // 2. 生成全新 nodes/edges 数组，避免引用复用导致 G6 不刷新
    const nodes = Object.values(nodeMap.value).map(node => ({ ...node }));
    const edgesCopy = edges.value.map(edge => ({ ...edge }));
    console.log('nodes', nodes, edgesCopy, nodeMap.value);
    // 3. 用 setData 更新 G6 数据，render 强制刷新画布
    if (typeof graph.setData === 'function') {
        // 重新设置数据
        graph.setData({ nodes, edges: edgesCopy });
        graph.render(); // setData 后手动 render，确保画布刷新
    } else {
        console.error('graph 实例没有 setData 方法', graph.setData);
    }
}

// 组件挂载后初始化 G6 图实例
onMounted(() => {
    // 1. 创建 G6 图实例，指定容器、尺寸、初始数据、交互行为
    graph = new G6.Graph({
        container: container.value,
        width: 900,
        height: 400,
        // 自动排布
        layout: {
            type: 'dagre', // 或 'circular', 'force' 等
        },
        data: {
            nodes: Object.values(nodeMap.value),
            edges: edges.value
        },
        behaviors: ['drag-canvas', 'zoom-canvas', 'drag-element'], // 支持拖动画布、缩放、拖拽节点
    });
    graph.render(); // 初始渲染
    console.log('graph', graph, nodeMap.value);
    // 2. 监听节点拖拽结束事件，实时同步节点坐标到 nodeMap
    graph.on('node:dragend', (evt: any) => {
        console.log('evt', evt);
        if (!evt.item) return; // 判空，防止报错
        const model = evt.item.getModel();
        // 生成新 nodeMap，保持响应式
        nodeMap.value = {
            ...nodeMap.value,
            [model.id]: {
                id: model.id,
                label: model.label,
                x: model.x,
                y: model.y
            }
        };
        console.log('nodeMap.value', nodeMap.value);
    });
});

// 添加节点方法：生成新节点和新边，整体替换数据，最后刷新 G6
function addNode() {
    nodeCount++;
    const newId = `node${nodeCount}`;
    // 1. 生成新 nodeMap，添加新节点
    nodeMap.value = {
        ...nodeMap.value,
        [newId]: {
            id: newId,
            label: `节点${nodeCount}`,
            x: 100 + nodeCount * 100,
            y: 200
        }
    };
    // 2. 生成新 edges，添加新边
    edges.value = [
        ...edges.value,
        {
            source: `node${nodeCount - 1}`,
            target: newId
        }
    ];
    console.log('nodeMap.value', nodeMap.value, edges.value);
    // 3. 刷新 G6 画布
    safeUpdate();
}
</script>